import AMap from 'AMap'
import AMapStyle from './amap-style'

export class MapContainer {
  constructor(options) {
    // 逆地理编码实例
    this.geocoder = new AMap.Geocoder()
    // 海量点实例集合
    this.massMarksMap = new Map()
    // 覆盖物集合实例集合
    this.overlayGroupMap = new Map()
    // 聚合覆盖物实例集合
    this.clusterMarkersMap = new Map()
    // init
    this.initMap(options)
    // 存放不同的信息窗口
    this.infoWindowMap = {}
    this.markers = []
    this.markersId = new Set()
  }

  /**
   *初始化地图
   * @param {Object} options 参数配置与高德的相同
   * @memberof MapContainer
   */
  initMap(options) {
    const map = new AMap.Map(
      options.target,
      Object.assign({
        center: [ 120.199572, 30.208193 ],
        zooms: [ 12, 15 ],
        expandZoomRange: true,
        ...options
      })
    )
    this.map = map
  }

  /**
   * 添加海量点
   * @param {String} {type} 图层类型，用于管理多类型图标切换的情况
   * @param {Array} {data} 点位数据
   * @param {Object} {options} 高德MassMarks 类配置
   * @param {Function} {clickCallback} 点位点击后的回调
   * @memberof MapContainer
   */
  addMassMarks({type, data, options = {}, clickCallback}) {
    if (this.massMarksMap.has(type)) {
      const mass = this.massMarksMap.get(type)
      mass.setData(data)
    } else {
      const mass = new AMap.MassMarks(data, {
        ...options,
        style: AMapStyle[type]
      })
      clickCallback && mass.on('click', clickCallback)
      mass.setMap(this.map)
      this.massMarksMap.set(type, mass)
    }
  }

  /**
   * 切换海量点涂层显示隐藏
   * @param {String} type 点位类型
   * @param {Boolean} show 显示隐藏
   */
  changeMassTypeShow(type, show) {
    if (this.massMarksMap.has(type)) {
      const mass = this.massMarksMap.get(type)
      show ? mass.show() : mass.hide()
    }
  }

  /**
   * 获取海量点数据
   * @param {String} type 海量点类型
   */
  getMassTypeData(type) {
    if (this.massMarksMap.has(type)) {
      const mass = this.massMarksMap.get(type)
      return mass.getData()
    } else {
      console.log('no has this type!!')
      return []
    }
  }

  clearMassType(type) {
    if (this.massMarksMap.has(type)) {
      const mass = this.massMarksMap.get(type)
      mass.setMap(null)
      this.massMarksMap.set(type, null)
    } else {
      console.log('no has this type!!')
    }
  }

  /**
   * 重新渲染海量点
   * @param {String} {type} 图层类型，用于管理多类型图标切换的情况
   * @memberof MapContainer
   */
  renderMassMarks(type) {
    if (this.massMarksMap.has(type)) {
      const mass = this.massMarksMap.get(type)
      mass.setStyle(AMapStyle[type])
    }
  }

  /**
   * 生成轨迹并回放轨迹
   * @param {Array} pathData 轨迹数据
   */

  addTrackReshow({path = [], moveEndCallback, speedNum}) {
    // 清除上次移动点位，上次轨迹
    this.movePoint && this.movePoint.stopMove()
    this.movePoint && this.movePoint.setMap(null)
    this.movePoint = null
    this.overlayGroupMap.get('track') && this.overlayGroupMap.get('track').setMap(null)
    this.overlayGroupMap.set('track', null)

    // 轨迹长度小于2不处理
    if (path.length < 2) {
      return
    }

    // 生成路径线
    const movePolyline = new AMap.Polyline({
      path,
      strokeColor: 'rgba(0,197,148,1)',
      strokeOpacity: 1,
      strokeWeight: 4,
      strokeStyle: 'solid',
      lineJoin: 'round',
      lineCap: 'square',
      zIndex: 50
    })

    // 实例化涂层组
    const OverlayGroup = new AMap.OverlayGroup([ movePolyline ])
    this.overlayGroupMap.set('track', OverlayGroup)
    OverlayGroup.setMap(this.map)
    this.map.setFitView(movePolyline)

    // 生成移动点位
    this.movePoint = new AMap.Marker({
      map: this.map,
      position: path[0],
      // icon: (process.env.VUE_APP_BASEURL || '') + '/mapIcon/car-po.png',
      // offset: new AMap.Pixel(-26, -13),
      autoRotation: false
      // angle: -90
    })
    this.movePoint.on('movealong', () => {
      moveEndCallback && moveEndCallback()
    })
    speedNum = speedNum || 1
    console.log(speedNum)
    this.movePoint.moveAlong(path, 200 * speedNum)
    return OverlayGroup
  }

  /**
   *  鼠标工具
   * @param {String} type 类型
   * @param {Object} styleOption 样式配置
   * @param {Boolean} clearPoly 是否保留覆盖物实例
   * @param {function} callback 回调函数
   */
  mouseToolDraw(type, styleOption = {}, clearPoly, callback) {
    this.mouseTool && this.mouseTool.close(true)
    const hasType = [ 'polyline', 'polygon', 'circle', 'rectangle' ].includes(type)
    if (!hasType) {
      throw new Error('type is required and in [\'polyline\', \'polygon\', \'circle\']')
    }
    this.mouseTool = new AMap.MouseTool(this.map)

    this.mouseTool.on('draw', function ({obj}) {
      // 是否保留覆盖物实例
      this.mouseTool && this.mouseTool.close(!!clearPoly)
      // 把画出的实例作为参数
      callback && callback(obj)
    }.bind(this))
    this.mouseTool[type]({

      strokeColor: '#4169E1',
      strokeOpacity: 1,
      strokeWeight: 4,
      // 折线样式还支持 'dashed'
      strokeStyle: 'dashed',
      // strokeStyle是dashed时有效
      strokeDasharray: [ 10, 5 ],
      lineJoin: 'round',
      lineCap: 'round',
      zIndex: 50,
      ...styleOption
    })
  }

  /**
   * 清除鼠标画的poly
   */
  clearMouseToolDraw() {
    this.mouseTool && this.mouseTool.close(true)
  }

  /**
   * 生成折线编辑器
   * @param {String} { type } 类型
   * @param {Array} { path } 折线或多边形数据
   * @param {Object} { styleOption } 折线或多边形样式
   * @param {function} { addNodeCallback } 增加节点回调
   * @param {function} { adjustCallback } 移动节点回调
   * @param {function} { endCallback } 结束编辑回调
   */
  newPolyEditor({
                  type,
                  path,
                  styleOption = {},
                  addNodeCallback,
                  adjustCallback,
                  endCallback,
                  drawCallback
                }) {
    // 结束编辑事件
    this.polyEditor && this.polyEditor.close()
    this.poly && this.poly.setMap(null)
    this.poly = null

    const fn = (poly) => {
      this.poly = poly
      this.poly.setMap(this.map)

      // 缩放地图到合适的视野级别
      this.map.setFitView([ this.poly ])
      // 初始化编辑器
      this.polyEditor = new AMap.PolyEditor(this.map, this.poly)

      //  添加节点事件
      this.polyEditor.on('addnode', function (event) {
        console.log('addnode')

        addNodeCallback && addNodeCallback(event)
      })
      // 节点改变事件
      this.polyEditor.on('adjust', function (event) {
        console.log('adjust')
        adjustCallback && adjustCallback(event)
      })
      // 结束编辑事件
      this.polyEditor.on('end', function (event) {
        console.log('end')
        endCallback && endCallback(event)
        // event.target 即为编辑后的折线对象
      })

      this.polyEditor.open()
      drawCallback && drawCallback(this.polyEditor)
    }

    if (path) {
      let poly = null
      if (type === 'polyline') {
        poly = new AMap.Polyline({
          path,
          strokeColor: '#4169E1',
          strokeOpacity: 1,
          strokeWeight: 4,
          // 折线样式还支持 'dashed'
          strokeStyle: 'dashed',
          // strokeStyle是dashed时有效
          strokeDasharray: [ 10, 5 ],
          lineJoin: 'round',
          lineCap: 'round',
          zIndex: 50,
          ...styleOption
        })
      } else if (type === 'polygon') {
        poly = new AMap.Polygon({
          path,
          strokeColor: '#4169E1',
          fillColor: '#4169E1',
          fillOpacity: 0.2,
          strokeOpacity: 1,
          strokeWeight: 4,
          // 折线样式还支持 'dashed'
          strokeStyle: 'dashed',
          // strokeStyle是dashed时有效
          strokeDasharray: [ 10, 5 ],
          lineJoin: 'round',
          lineCap: 'round',
          zIndex: 50,
          ...styleOption
        })
      }
      fn(poly)
    } else {
      this.mouseToolDraw(type, styleOption, false, fn)
    }
  }

  /**
   * 添加聚合点位
   *
   * @param {Array} { data } 点位数据
   * @param {String} { type } 点位类型
   * @param {Object} { markerOpt } 点配置
   * @param {Function} { markerClickCallback } 坐标点点击回调
   * @param {Object} { options } 聚合配置
   * @memberof MapContainer
   */
  addMarkerClusterer({data, type = 'default', markerOpt, markerClickCallback, options}) {
    const markers = data.map(item => {
      const icon = AMapStyle.clusterMarker[item.iconName]
      const marker = new AMap.Marker({
        position: new AMap.LngLat(item.lon, item.lat),
        extData: item,
        icon: new AMap.Icon(icon),
        offset: icon.offset || [ 0, 0 ],
        ...markerOpt
      })

      markerClickCallback && marker.on('click', markerClickCallback)

      return marker
    })

    // clusterMarkersMap 分类管理聚合点数据
    let clusterMarkers = this.clusterMarkersMap.get(type)
    window.clusterMarkersMap = this.clusterMarkersMap

    if (clusterMarkers) {
      clusterMarkers.setMarkers(markers)
    } else {
      clusterMarkers = new AMap.MarkerClusterer(this.map, markers, {
        styles: AMapStyle.clusterStyle,
        maxZoom: 15,
        ...options
      })
      this.clusterMarkersMap.set(type, clusterMarkers)
    }
  }

  /**
   * 激活图标，不传则只恢复上个图标
   * @param {*} marker 点实例
   * @param {String} iconName icon名
   */
  setMarkerClustererIcon(marker, isTreeClick) {
    if (isTreeClick && this.lastMarker && (this.lastMarker._amap_id === marker._amap_id)) return
    this.lastMarker && this.lastMarker.setIcon(this.lastMarkerIcon)
    if (!marker || (this.lastMarker && (this.lastMarker._amap_id === marker._amap_id))) {
      this.lastMarkerIcon = null
      this.lastMarker = null
      return
    }
    this.lastMarkerIcon = marker.getIcon()
    this.lastMarker = marker
    marker.setIcon(new AMap.Icon(AMapStyle.clusterMarker[marker.getExtData().iconName + '-ac']))
  }

  // 判断当前点击的带你是不是上一个点
  isLastMarker(marker) {
    return this.lastMarker && (this.lastMarker._amap_id === marker._amap_id)
  }

  // 清除聚合点
  clearAllClusterMarker() {
    for (var map of this.clusterMarkersMap) { // 遍历Map
      map[1].clearMarkers()
    }
  }

  // 添加单个激活点
  changeActivePoint(data, markerClickCallback) {
    this.activePoint && this.activePoint.setMap(null)
    this.activePoint = null
    if (data) {
      const icon = AMapStyle.clusterMarker[(data.iconName || data.type) + '-ac']
      this.activePoint = new AMap.Marker({
        position: new AMap.LngLat(data.longitude, data.latitude),
        extData: data,
        icon: new AMap.Icon(icon),
        offset: icon.offset || [ 0, 0 ]
      })
      this.activePoint.on('click', (data) => {
        markerClickCallback && markerClickCallback(data)
        this.activePoint && this.activePoint.setMap(null)
        this.activePoint = null
      })
      this.activePoint.setMap(this.map)
    }
  }

  /**
   *
   * @param {Array} data 数据
   * @param {Number} radius 点半径
   * @param {Array} opacity 透明度数组
   */
  addHeatMap(data, radius, opacity) {
    if (!this.heatmap) {
      this.heatmap = new AMap.Heatmap(this.map, {
        radius: radius || 25, // 给定半径
        opacity: opacity || [ 0, 0.8 ]
      })
    }
    this.heatmap.setDataSet({
      data: data
      // max: 100
    })
  }

  /**
   *打开信息弹窗
   * @param {String/HTMLElement} { target } // 显示内容，可以是HTML要素字符串或者HTMLElement对象
   * @param {*} { longitude } // 经度
   * @param {*} { latitude } // 纬度
   * @param {Array} { offset } // 信息窗体显示位置偏移量。默认基准点为信息窗体的底部中心（若设置了anchor，则以anchor值为基准点）。
   * @param {Function} { closeCallback } // 关闭弹窗的回调
   * @memberof MapContainer
   */
  openInfoWindow({target, longitude, latitude, offset, closeWhenClickMap = true, closeCallback}) {
    const position = new AMap.LngLat(longitude, latitude)
    if (this.infoWindow) {
      this.infoWindow.close()
      this.infoWindow.setPosition(position)
      this.infoWindow.setContent(target)
    } else {
      this.infoWindow = new AMap.InfoWindow({
        isCustom: true, // 使用自定义窗体
        content: target,
        position,
        autoMove: true,
        closeWhenClickMap: closeWhenClickMap,
        offset: new AMap.Pixel(offset[0], offset[1])
      })
    }
    // 清除上一次的关闭回调
    this.infoWindow._oldCallback && this.infoWindow.off('close', this.infoWindow._oldCallback)
    // 将关闭回调保存下来
    this.infoWindow._oldCallback = closeCallback
    closeCallback && this.infoWindow.on('close', closeCallback)

    this.infoWindow.open(this.map, position)
  }

  /**
   * 清除信息窗口
   */
  clearInfoWindow() {
    if (this.infoWindow) {
      this.infoWindow.close()
      // 清除上一次的关闭回调
      this.infoWindow._oldCallback && this.infoWindow.off('close', this.infoWindow._oldCallback)
    }
  }

  // 移动地图到指定位置
  setCenterPosition(lnglat, zoom = this.map.getZoom()) {
    this.map.setZoomAndCenter(zoom, lnglat)
  }

  /**
   * 设置默认地图点位
   * @param {Number} {longitude} 经度
   * @param {Number} {latitude} 纬度
   * @param {Icon} {icon} 点位图标
   * @memberof MapContainer
   */
  setLocaltion({
                 longitude,
                 latitude,
                 toCenter,
                 icon = new AMap.Icon(AMapStyle.location),
                 options
               }) {
    this.clearLocaltion()

    this.localtionMarker = new AMap.Marker({
      icon,
      position: new AMap.LngLat(longitude, latitude),
      ...options
    })
    this.localtionMarker.setMap(this.map)
    if (toCenter) {
      this.setCenterPosition([ longitude, latitude ], this.map.getZoom())
    }
  }

  // 清除定位点击点位
  clearLocaltion() {
    this.localtionMarker && this.localtionMarker.setMap(null)
    this.localtionMarker = null
  }

  getLocation() {
    const mapObj = new AMap.Map('iCenter')
    mapObj.plugin('AMap.Geolocation', () => {
      const geolocation = new AMap.Geolocation({
        enableHighAccuracy: true,
        timeout: 10000,
        maximumAge: 0,
        convert: true,
        showButton: true,
        buttonPosition: 'LB',
        buttonOffset: new AMap.Pixel(10, 20),
        showMarker: true,
        showCircle: true,
        panToLocation: true,
        zoomToAccuracy: true
      })
      mapObj.addControl(geolocation)
      geolocation.getCurrentPosition()
      AMap.event.addListener(geolocation, 'complete', (e) => {
        this.setLocaltion({longitude: e.position.lng, latitude: e.position.lat, toCenter: true})
      })
    })
  }
}

/**
 * 逆地理编码
 * @param {Array} lnglat
 */
export function getAddressByLnglat(lnglat, callback) {
  const geocoder = new AMap.Geocoder({
    city: '杭州', // 城市设为北京，默认：“全国”
    radius: 1000 // 范围，默认：500
  })
  geocoder.getAddress(lnglat, function (status, result) {
    if (status === 'complete' && result.regeocode) {
      callback && callback(result.regeocode.formattedAddress)
    } else {
      console.log('根据经纬度查询地址失败')
    }
  })
}

MapContainer.getAddressByLnglat = getAddressByLnglat

export default MapContainer
